package com.idanchuang.component.redis;

import com.idanchuang.component.redis.listener.AcgAsyncTaskExecutor;
import com.idanchuang.component.redis.listener.KeyExpiredProcessor;
import com.idanchuang.component.redis.listener.RedisClusterKeyEventExpiredListener;
import com.idanchuang.component.redis.listener.RedisKeyEventExpiredListener;
import io.lettuce.core.AbstractRedisClient;
import io.lettuce.core.cluster.RedisClusterClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;

import java.lang.reflect.Field;

/**
 * @author yjy
 * Created at 2021/9/14 10:33 上午
 */
@Configuration
@ConditionalOnProperty(value = "spring.redis.listener.dc.enabled", havingValue = "true", matchIfMissing = true)
public class ComponentRedisListenerConfiguration {

    private static final Logger logger = LoggerFactory.getLogger(ComponentRedisListenerConfiguration.class);

    @Bean
    public RedisKeyEventExpiredListener componentRedisKeyEventExpiredListener(RedisProperties redisProperties,
                                                                     @Autowired(required = false) RedisMessageListenerContainer redisMessageListenerContainer,
                                                                     RedisConnectionFactory redisConnectionFactory,
                                                                     @Autowired(required = false) KeyExpiredProcessor processor) {
        if (processor == null) {
            return null;
        }
        if (redisMessageListenerContainer == null) {
            redisMessageListenerContainer = new RedisMessageListenerContainer();
            redisMessageListenerContainer.setConnectionFactory(redisConnectionFactory);
            redisMessageListenerContainer.afterPropertiesSet();
            redisMessageListenerContainer.start();
        }
        // 防止线程数过多
        redisMessageListenerContainer.setTaskExecutor(new AcgAsyncTaskExecutor());
        return new RedisKeyEventExpiredListener(redisProperties, redisMessageListenerContainer, processor);
    }

    @Bean
    @ConditionalOnProperty(name = "spring.redis.cluster.nodes")
    public RedisClusterKeyEventExpiredListener redisClusterKeyEventExpiredListener(LettuceConnectionFactory lettuceConnectionFactory,
                                                                                   @Autowired(required = false) KeyExpiredProcessor processor) {
        if (processor == null) {
            return null;
        }
        try {
            Field field = LettuceConnectionFactory.class.getDeclaredField("client");
            field.setAccessible(true);
            AbstractRedisClient client = (AbstractRedisClient) field.get(lettuceConnectionFactory);
            if (client instanceof RedisClusterClient) {
                return new RedisClusterKeyEventExpiredListener((RedisClusterClient) client, processor);
            }
        } catch (Exception e) {
            logger.error("redisClusterKeyEventExpiredListener declare failed", e);
        }
        return null;
    }

}
